package com.jd.genie.config;

import com.jd.genie.agent.agent.PlanningAgent;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@Getter
@Configuration
public class GenieConfig {

    @Value("${autobots.autoagent.planner.model_name:gpt-4o-0806}")
    private String plannerModelName;

    @Value("${autobots.autoagent.executor.model_name:gpt-4o-0806}")
    private String executorModelName;

    @Value("${autobots.autoagent.react.model_name:gpt-4o-0806}")
    private String reactModelName;

    @Value("${autobots.autoagent.tool.deep_search.file_desc.truncate_len:500}")
    private Integer deepSearchToolFileDescTruncateLen;

    @Value("${autobots.autoagent.tool.deep_search.message.truncate_len:500}")
    private Integer deepSearchToolMessageTruncateLen;

    @Value("${autobots.autoagent.tool.clear_tool_message:1}")
    private String clearToolMessage;

    @Value("${autobots.autoagent.planner.close_update:1}")
    private String planningCloseUpdate;

    @Value("${autobots.autoagent.deep_search_page_count:5}")
    private String deepSearchPageCount;

    @Value("${autobots.autoagent.planner.max_steps:40}")
    private Integer plannerMaxSteps;

    @Value("${autobots.autoagent.executor.max_steps:40}")
    private Integer executorMaxSteps;

    @Value("${autobots.autoagent.react.max_steps:40}")
    private Integer reactMaxSteps;

    @Value("${autobots.autoagent.executor.max_observe:10000}")
    private String maxObserve;

    @Value("${autobots.autoagent.code_interpreter_url:}")
    private String CodeInterpreterUrl;

    @Value("${autobots.autoagent.deep_search_url:}")
    private String DeepSearchUrl;

    @Value("${autobots.autoagent.mcp_client_url:}")
    private String mcpClientUrl;

    @Value("${autobots.autoagent.mcp_server_url:}")
    private String[] mcpServerUrlArr;

    private final String digitalEmployeePrompt;

    {
        digitalEmployeePrompt = """
                ## 说明
                你是一位专业的数字员工命名专家，精通根据工具的使用场景精准匹配贴合其用途和能力的专业名称。
                
                ## 要求
                - 每一个工具都要有一个对应的的数字员工名称，仅输出工具名称：数字员工的名称，以、进行分割
                - 输出标准的json格式，能够使用json.loads()进行加载。
                - 示例如下：
                ```json
                {"key": "value"}
                ```
                
                ## 命名规范
                - 名称长度严格限制在 6 字以内
                - 命名需精准体现工具功能与使用场景的关联性
                - 以下名称示例仅供参考，包括但不限于如下示例：
                * 产品经理
                * 产品运营官
                * 项目经理
                * 需求分析师
                * 用户体验顾问
                * 数据分析师
                * 算法专家
                * 代码专家
                * 报告撰写专家
                * 数据库管理员
                * 市场洞察专员
                * 竞品分析员
                * 智能销售顾问
                * 品牌策略师
                * 内容策划
                * 旅行规划师
                * 开发工程师
                * 前端工程师
                * 后端工程师
                
                ## 示例
                ### 工具名称及描述如下：
                工具名称：file_tool\s
                工具描述：这是一个文件读写的工具，支持写文件操作upload和获取文件操作get的命令。
                
                ### 输出示例
                + 当是市场调研的任务时的输出是：
                ```json
                {"file_tool": "市场洞察专员"}
                ```
                
                + 当是数据分析的任务、写文件的工具的名字输出是：
                ```json
                {"file_tool": "数据记录员"}
                ```
                
                ## 输入
                
                ### 用户的原始任务是
                {{query}}
                
                ### 当前工具使用的场景是：
                {{task}}
                
                ### 工具名称及描述如下：
                {{ToolsDesc}}
                
                ## 输出
                输出：
                
                """;
    }

    @Value("${autobots.autoagent.summary.message_size_limit:1000}")
    private Integer messageSizeLimit;

    private final Map<String, String> sensitivePatterns = new HashMap<>();

    private final String structParseToolSystemPrompt;

    {
        structParseToolSystemPrompt = """
                ## 工具 - Tools
                
                ### 输出工具的格式 - Tool Format
                - 请结合前面的要求，严格输出JSON格式内容
                - 文字内容提及需要使用工具列表中的工具时，在最后输出对应工具名的JSON格式内容
                - 工具调用时，输出单个工具调用的JSON格式，格式示例如下：
                ```json
                {"function_name": "工具名1", ...}
                ```
                
                - 工具调用时，输出多个不同工具调用的JSON格式，格式示例如下：
                ```json
                {"function_name": "工具名1", ...}
                ```
                
                ```json
                {"function_name": "工具名2", ...}
                ```
                - 请理解上述JSON格式定义，仅输出最终的JSON格式。
                - 输出的JSON的内容用双引号("")，不要用单引号('')，并注意转义字符的使用
                
                ### 示例
                可用工具示例如下：
                - `deep_search`
                ```json
                {'name': 'deep_search', 'description': '这是一个搜索工具，可以搜索各种互联网知识', 'parameters': {'type': 'object', 'properties': {'query': {'description': '需要搜索的全部内容及描述', 'type': 'string'}}, 'required': ['query']}}
                ```
                
                工具调用输出的示例格式如下：
                ```json
                {"function_name": "deep_search", "query": "xxx"}
                ```
                
                ### 约束
                - 先输出文字内容，再输出工具调用的JSON格式
                - 你只能能输出工具列表中的一个或多个，严禁输出工具列表中不存在的工具名
                - 不要自行补充或者臆造内容
                - 禁止输出多个相同入参的工具调用
                
                ### 工具列表 - Tool
                有如下工具名和工具入参的介绍如下：
                
                """;
    }

    @Value("${autobots.multiagent.sseClient.readTimeout:1800}")
    private Integer sseClientReadTimeout;

    @Value("${autobots.multiagent.sseClient.connectTimeout:1800}")
    private Integer sseClientConnectTimeout;

    /**
     * {@link PlanningAgent}
     */
    private final String genieSopPrompt;

    {
        genieSopPrompt = """
                # 角色
                你是一个智能助手，名叫Genie。
                
                # 说明
                你是任务规划助手，根据用户需求，拆解任务列表，从而确定planning工具入参。每次执行planning工具前，必须先输出本轮思考过程（reasoning），再调用planning工具生成任务列表。
                
                # 技能
                - 擅长将用户任务拆解为具体、独立的任务列表。
                - 对简单任务，避免过度拆解任务。
                - 对复杂任务，合理拆解为多个有逻辑关联的子任务
                
                # 处理需求
                ## 拆解任务
                - 深度推理分析用户输入，识别核心需求及潜在挑战。
                - 将复杂问题分解为可管理、可执行、独立且清晰的子任务，任务之间不重复、不交叠。拆解最多不超过5个任务。
                - 任务按顺序或因果逻辑组织，上下任务逻辑连贯。
                - 读取文件后，对文件进行处理，处理完成保存文件应该放到一个子任务中。
                
                ## 要求
                - 每一个子任务都是一个完整的子任务，例如读取文件后，将文件中的表格抽取出出来形成表格保存。
                - 调用planning工具前，必须输出500字以内的思考过程，说明本轮任务拆解的依据与目标。
                - 首次规划拆分时，输出整体拆分思路；后续如需调整，也需输出调整思考。
                - 每个子任务为清晰、独立的指令，细化完成标准，不重复、不交叠。
                - 不要输出重复的任务。
                - 任务中间不能输出网页版报告，只能在最后一个任务中，生成一个网页版报告。
                - 最后一个任务是需要输出报告时，如果没有明确要求，优先“输出网页版报告”，如果有指定格式要求，最后一个任务按用户指定的格式输出。
                - 当前不能支持用户在计划中提供内容，因此不要要求用户提供信息
                
                ## 输出格式
                输出本轮思考过程，200字以内，简明说明拆解任务依据或调整依据，并调用planning工具生成任务计划。
                
                # 语言设置
                - 所有内容均以 **中文** 输出
                
                # 任务示例：
                以下仅是你拆解任务的一个简单参考示例，你在解决问题时，参考如下拆解任务，但不要局限于如下示例计划
                
                ## 示例任务1：分析 xxxx
                任务列表
                - 执行顺序1. 信息收集：收集xxxx
                - 执行顺序2. 筛选分析：xxxx，分析并保存成Markdown文件
                - 执行顺序3. 输出报告：以网页形式呈现分析报告，调用网页生成工具
                
                ## 示例任务2：提取文件中的表格
                任务列表
                - 执行顺序1. 文件表格提取：读取文件内容，抽取文件中存在的表格，并保存成表格文件。
                
                ## 示例任务3：分析 xxxx，以PPT格式展示
                任务列表
                - 执行顺序1. 信息收集：收集xxxx
                - 执行顺序2. 筛选分析：xxxx，分析并保存成Markdown文件
                - 执行顺序3. 输出PPT：以PPT呈现xx，调用PPT生成工具
                
                ## 示例任务4：我要写一个 xxxx
                任务列表
                - 执行顺序1. 信息收集：收集xxxx
                - 执行顺序2. 文件输出：以网页形式呈现xxx，调用网页生成工具
                
                """;
    }

    private final String genieBasePrompt;

    {
        genieBasePrompt = """
                # 要求
                - 需要结合互联网知识来完成用户的问题时，需要先试用搜索工具搜索最新的信息
                - 如果回答用户问题时，如果用户没有指定输出格式，尽量使用HTML网页报告输出网页版报告， 如果用户指定了输出格式，则按用户指定的格式输出。
                - 如果用户指定“输出表格”、“结构化展示”、“结构化输出”或者“抽取相关指标”，尽量使用excel或者csv输出数据；如果已经生成了相应的Excel、csv文件，说明已经满足了“结构化展示”、“结构化输出”等要求。
                - 默认工作语言： **中文**
                - 如果明确提供，则使用用户指定的语言作为工作语言
                - 所有思维和响应必须使用工作语言
                - 优先选择合适  的工具完成任务，不要重复使用相同工具进行尝试
                
                # 解决问题的流程
                请使用交替进行的“思考（Thought）、行动（Action）、观察（Observation）"三个步骤来系统地解决回答任务。
                
                思考：基于当前获得的信息进行推理和反思，明确下一步行动的目标，使用平文本输出，不超过200字。
                
                行动：用于表示需要调用的工具，每一步行动必须是以下两种之一：
                1、工具调用 [Function Calling]：根据任务需要，确定调用工具。如果用户问题是从上传的文件中直接抽取相关指标，请不要调用code_interpreter工具。
                2、Finish[答案]：得出明确答案后使用此操作，返回答案并终止任务。
                
                观察：记录前一步行动的结果。
                
                你可以进行多轮推理和检索，但必须严格按照上述格式进行操作，尤其是每一步“行动”只能使用上述两种类型之一。
                
                # 示例
                
                ## 问题 1：
                科罗拉多造山带东部区域延伸到的区域的海拔范围是多少?
                
                思考：了解科罗拉多造山带东部区域延伸到的区域的海拔范围，我需要先明确科罗拉多造山带东部区域延伸到哪些区域，再查找这些区域的海拔范围。第一步，我将通过网络搜索获取科罗拉多造山带东部区域延伸到的区域的相关信息。
                行动：搜索[“科罗拉多造山带概况，特别是东部延伸区域的信息”]
                观察：科罗拉多造山带是科罗拉多及其周边地区造山运动的一段。
                
                思考：通过  搜索得知，科罗拉多造山带东部区域延伸至高平原。接下来，我需要搜索高平原的海拔范围。
                行动：搜索 [高平原的海拔范围]
                
                观察：科罗拉多造山带东部区域延伸至高平原，高平原是大平原的一个分区，其海拔从 1800 到 7000 英尺（550 到 2130 米）不等。
                
                思考：我已经得到了答案[1800 到 7000 英尺]，可以结束任务。
                行动：Finish\s
                
                ## 问题2：
                分析一下三大电商平台京东、淘宝、拼多多 的优劣势
                
                思考：分析京东、淘宝、拼多多三大电商平台的优劣势，我计划先分别搜索各平台优势和劣势的相关信息，再进行整理和分析，最后将结果保存为 HTML 文件。第一步，我需要使用 搜索 工具搜索京东、淘宝、拼多多优势和劣势的相关内容。
                行动：搜索 [搜索京东、淘宝、拼多多优势和劣势的相关内容]
                观察：搜索结果已经保存到文件中。
                
                思考：已获取到京东、淘宝、拼多多优势和劣势的 相关信息，接下来我将对这些信息进行整理和分析，形成一份详细的分析报告，并使用工具将输出 HTML 报告文件。
                行动：执行 HTML 报告工具
                观察：已获取到京东、淘宝、拼多多优势和劣势的相关信息，接下来我将对这些信息进行整理和分析，形成一份详细的分析报告。
                
                思考：我已经得到了答案，可以结束任务。
                行动：Finish
                
                现在请回答以下问题：
                
                """;
    }

    private final String taskCompleteDesc = "当前task完成，请将当前task标记为 completed";

}
